package com.chainyoung.component_tmmarket.ui;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.chainyoung.common.base.BaseFragment;
import com.chainyoung.common.bean.ReqModel;
import com.chainyoung.common.di.AppComponent;
import com.chainyoung.common.event.BaseEvent;
import com.chainyoung.common.http.JsonConventUtils;
import com.chainyoung.common.http.websocket.WebSoketUtils;
import com.chainyoung.common.http.websocket.WsManager;
import com.chainyoung.common.http.websocket.WsStatus;
import com.chainyoung.common.http.websocket.WsStatusListener;
import com.chainyoung.common.utils.ScreenUtils;
import com.chainyoung.component_tmmarket.R;
import com.chainyoung.component_tmmarket.R2;
import com.chainyoung.component_tmmarket.bean.Kline;
import com.chainyoung.component_tmmarket.bean.KlineTotal;
import com.chainyoung.component_tmmarket.bean.MarketTotal;
import com.chainyoung.component_tmmarket.utils.ChartUtils;
import com.chainyoung.component_tmmarket.utils.chart.CoupleChartGestureListener;
import com.github.mikephil.charting.charts.BarChart;
import com.github.mikephil.charting.charts.Chart;
import com.github.mikephil.charting.charts.CombinedChart;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.CandleEntry;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.listener.ChartTouchListener;
import com.github.mikephil.charting.listener.OnChartGestureListener;
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import org.simple.eventbus.EventBus;
import org.simple.eventbus.Subscriber;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
import okhttp3.Response;
import okio.ByteString;


public class MarketKlineFragment extends BaseFragment {

    @BindView(R2.id.candle_stick_chart)
    CombinedChart candleStickChart;
    @BindView(R2.id.bar_chart)
    BarChart barChart;
    @BindView(R2.id.rl_data)
    RelativeLayout rlData;
    @BindView(R2.id.tv_time)
    TextView tvTime;
    @BindView(R2.id.tv_open)
    TextView tvOpen;
    @BindView(R2.id.tv_high)
    TextView tvHigh;
    @BindView(R2.id.tv_low)
    TextView tvLow;
    @BindView(R2.id.tv_close)
    TextView tvClose;
    @BindView(R2.id.tv_vol)
    TextView tvVol;
    @BindView(R2.id.tv_change)
    TextView tvChange;
    @BindView(R2.id.tv_change_percent)
    TextView tvChangePercent;


    private String TAG = getClass().getSimpleName();

    public static final String TYPE_MINUTE = "60";//分时线
    public static final String TYPE_15_MINUTE = "900";//15分
    public static final String TYPE_ONE_HOUR = "3600";//1小时
    public static final String TYPE_FOUR_HOUR = "14400";//4小时
    public static final String TYPE_DAY = "86400";//日线

    private String type;//k线图类型 分时 15分 1小时 4小时 日线
    private String currencyIn, currencyOut;

    private WsManager wsManager;
    //private WsStatusListener wsStatusListener;

    private boolean isVisiable;
    private boolean isAlreadySubed = false;
    private int width;
    SimpleDateFormat dfs;
    //private String lastPrice;

    public static MarketKlineFragment newInstance(String type, String currencyIn, String currencyOut) {
        MarketKlineFragment fragment = new MarketKlineFragment();
        Bundle args = new Bundle();
        args.putString("type", type);
        args.putString("currencyIn", currencyIn);
        args.putString("currrencyOut", currencyOut);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        if (getArguments() != null) {
            type = getArguments().getString("type");
            currencyIn = getArguments().getString("currencyIn");
            currencyOut = getArguments().getString("currrencyOut");
        }
    }

    @Override
    protected void setupFragmentComponent(AppComponent appComponent) {

    }

    @Override
    protected boolean useLoadSir() {
        return true;
    }

    @Override
    protected void initUi() {
        super.initUi();
        wsManager = WebSoketUtils.getWsManager();
        width = ScreenUtils.getScreenWidth(mContext);
        setListener();
        dfs = new SimpleDateFormat("yyyy-MM-dd HH:mm");

    }

    private void setListener() {
        ChartUtils.initCandleChart(candleStickChart);
        ChartUtils.initBarChart(barChart);
        candleStickChart.setOnChartGestureListener(new CoupleChartGestureListener(candleStickChart, new Chart[]{barChart}, rlData));
        barChart.setOnChartGestureListener(new CoupleChartGestureListener(barChart, new Chart[]{candleStickChart}, rlData));
        candleStickChart.setDragDecelerationEnabled(false);
        barChart.setDragDecelerationEnabled(false);
        candleStickChart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {
            @Override
            public void onValueSelected(Entry e, Highlight h) {
                barChart.highlightValues(new Highlight[]{h});
                FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) rlData.getLayoutParams();
                if (h.getXPx() >= width / 2) {
                    params.gravity = Gravity.START;
                } else {
                    params.gravity = Gravity.END;
                }
                rlData.setVisibility(View.VISIBLE);
                rlData.setLayoutParams(params);
                // barChart.getBarData().getEntryForHighlight()
                BarEntry entry = (BarEntry) barChart.getBarData().getEntryForHighlight(h);
                Kline.DataBean data = (Kline.DataBean) entry.getData();
                updateShowData(data);
            }

            @Override
            public void onNothingSelected() {

            }
        });


        barChart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {
            @Override
            public void onValueSelected(Entry e, Highlight h) {
                candleStickChart.highlightValues(new Highlight[]{h});
                FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) rlData.getLayoutParams();
                if (h.getXPx() >= width / 2) {
                    params.gravity = Gravity.START;
                } else {
                    params.gravity = Gravity.END;
                }
                rlData.setVisibility(View.VISIBLE);
                rlData.setLayoutParams(params);
                BarEntry barEntry = (BarEntry) e;
                Kline.DataBean data = (Kline.DataBean) barEntry.getData();
                updateShowData(data);
            }

            @Override
            public void onNothingSelected() {

            }
        });

    }

    private void updateShowData(Kline.DataBean data) {
        tvTime.setText(dfs.format(new Date(data.getTime() * 1000)));
        tvHigh.setText(new BigDecimal(data.getHigh()).setScale(6, RoundingMode.DOWN).stripTrailingZeros().toPlainString());
        tvLow.setText(new BigDecimal(data.getLow()).setScale(6, RoundingMode.DOWN).stripTrailingZeros().toPlainString());
        tvOpen.setText(new BigDecimal(data.getOpen()).setScale(6, RoundingMode.DOWN).stripTrailingZeros().toPlainString());
        tvClose.setText(new BigDecimal(data.getClose()).setScale(6, RoundingMode.DOWN).stripTrailingZeros().toPlainString());
        tvVol.setText(new BigDecimal(data.getVol()).setScale(6, RoundingMode.DOWN).stripTrailingZeros().toPlainString());
        // lastPrice = ((MarketKLineActivity) getActivity()).getNewestPrice();
        double change = data.getClose() - data.getOpen();
        tvChange.setText(String.valueOf(new BigDecimal(change).setScale(6, BigDecimal.ROUND_DOWN)));
        tvChange.setTextColor(change > 0 ? ContextCompat.getColor(mContext, R.color._09C173) : change < 0 ? ContextCompat.getColor(mContext, R.color._F95A54) :
                ContextCompat.getColor(mContext, R.color._7E8CA6));
        String percent = String.valueOf(new BigDecimal(change / data.getOpen() * 100).setScale(2, BigDecimal.ROUND_DOWN));
        tvChangePercent.setText(String.format("%s%%", percent));
        tvChangePercent.setTextColor(change > 0 ? ContextCompat.getColor(mContext, R.color._09C173) : change < 0 ? ContextCompat.getColor(mContext, R.color._F95A54) :
                ContextCompat.getColor(mContext, R.color._7E8CA6));
    }

    @Override
    protected void initData() {

    }


    @Override
    protected void onFirstUserVisible() {
        isVisiable = true;
        wsManager.setWsStatusListener(new WsStatusListener() {

            @Override
            public void onMessage(ByteString bytes) {
                super.onMessage(bytes);
                String r = JsonConventUtils.byteBufferToString(bytes.asByteBuffer());
                try {
                    String result = JsonConventUtils.uncompress(r);
                    handleResult(result);
                    Log.d(TAG, result);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                EventBus.getDefault().post(new BaseEvent<>(BaseEvent.EventCode.WS_KLINE_OPEN));
            }

            @Override
            public void onFailure(Throwable t, Response response) {
                super.onFailure(t, response);

            }

            @Override
            public void onOpen(Response response) {
                super.onOpen(response);
                EventBus.getDefault().post(new BaseEvent<>(BaseEvent.EventCode.WS_KLINE_OPEN));
            }

        });
    }

    @Override
    public void onUserVisible() {
        super.onUserVisible();
        isVisiable = true;
        if (wsManager.getCurrentStatus() != WsStatus.CONNECTED) {
            wsManager.startConnect();
        }
        rlData.setVisibility(View.GONE);
    }


    @Override
    public void onUserInvisible() {
        super.onUserInvisible();
        if (wsManager.getCurrentStatus() == WsStatus.CONNECTED) {
            unsubMarketDetail();
            isAlreadySubed = false;
        }
        isVisiable = false;
    }

    private void subMarketDetail() {
        ReqModel reqModel = new ReqModel();
        reqModel.setType("sub");
        reqModel.setTopic(getMarketName());
        wsManager.sendMessage(new Gson().toJson(reqModel));
        isAlreadySubed = true;
    }

    private void reqMarketDetail() {
        ReqModel reqModel1 = new ReqModel();
        reqModel1.setType("req");
        reqModel1.setTopic(getMarketName());
        wsManager.sendMessage(new Gson().toJson(reqModel1));
    }

    private void unsubMarketDetail() {
        if (wsManager.getCurrentStatus() == WsStatus.CONNECTED) {
            ReqModel reqModel1 = new ReqModel();
            reqModel1.setType("unsub");
            reqModel1.setTopic(getMarketName());
            wsManager.sendMessage(new Gson().toJson(reqModel1));
            isAlreadySubed = false;
        }
    }

    private String getMarketName() {
        return new StringBuilder().append("market.").append(currencyIn.toLowerCase()).append("_").
                append(currencyOut.toLowerCase()).append(".kline.").append(type).toString();
    }

    private List<Long> timeList = new ArrayList<>();

    private void handleResult(String marketResult) {

        Gson gson = new Gson();
        Map<String, Object> map = new HashMap<String, Object>();
        map = gson.fromJson(marketResult, map.getClass());
        if (map.containsKey("topic") && map.get("topic").toString().endsWith(".market")) {
            MarketTotal marketTotal = null;
            try {
                marketTotal = gson.fromJson(marketResult, new TypeToken<MarketTotal>() {
                }.getType());
            } catch (Exception ignored) {

            }
            if (marketTotal == null || marketTotal.getTick() == null) {
                return;
            }

            EventBus.getDefault().post(new BaseEvent<>(BaseEvent.EventCode.WS_KLINE_OPEN, marketTotal));
        }
        KlineTotal klineTotal = null;

        try {
            klineTotal = gson.fromJson(marketResult, new TypeToken<KlineTotal>() {
            }.getType());
        } catch (Exception ignored) {

        }

        if (klineTotal != null && klineTotal.getType().equals("ping")) {
            //发送pong
            sendPong();
        }

        if (klineTotal == null || klineTotal.getTick() == null) {
            return;
        }

        showPageContent();
        String topic = klineTotal.getTopic();
        if (isVisiable && type.equals(klineTotal.getTopic().substring(topic.lastIndexOf(".") + 1))) {
            ChartUtils.notifyCandleDataSetChanged(candleStickChart, getCandleChartData(klineTotal), getMaData(klineTotal, 5), getMaData(klineTotal, 10), getMaData(klineTotal, 30), type, timeList);
            ChartUtils.notifyBarDataSetChanged(barChart, getBarChartData(klineTotal), type, timeList);
        }

    }

    private void sendPong() {
        ReqModel reqModel = new ReqModel();
        reqModel.setType("pong");
        wsManager.sendMessage(new Gson().toJson(reqModel));
    }

    private List<CandleEntry> getCandleChartData(KlineTotal klineTotal) {
        ArrayList<CandleEntry> values = new ArrayList<>();
        int i = 0;
        timeList.clear();
        for (Kline kline : klineTotal.getTick()) {
            values.add(new CandleEntry(i, (float) kline.getData().getHigh(), (float) kline.getData().getLow(),
                    (float) kline.getData().getOpen(), (float) kline.getData().getClose()));
            timeList.add(kline.getData().getTime());
            i++;
        }
        return values;
    }

    private List<Entry> getMaData(KlineTotal klineTotal, int maType) {
        ArrayList<Entry> data = new ArrayList<>();
        for (int i = 0; i < klineTotal.getTick().size(); i++) {
            if (i == 0) {
                data.add(new Entry(0, (float) klineTotal.getTick().get(0).getData().getClose()));
            } else if (i % maType == (maType - 1)) {
                data.add(new Entry(i, getMeanValue(i, klineTotal, maType)));
            } else if (i == klineTotal.getTick().size() - 1 && i % maType != (maType - 1)) {
                data.add(new Entry(klineTotal.getTick().size() - 1, (float) klineTotal.getTick().get(klineTotal.getTick().size() - 1).getData().getClose()));
            }
        }
        return data;
    }


    private float getMeanValue(int i, KlineTotal klineTotal, int maType) {
        float vol = 0.f;
        for (int j = i - (maType - 1); j < i + 1; j++) {
            vol += klineTotal.getTick().get(j).getData().getClose();
        }
        return vol / maType;
    }


    private List<BarEntry> getBarChartData(KlineTotal klineTotal) {
        ArrayList<BarEntry> values = new ArrayList<>();
        int i = 0;
        for (Kline kline : klineTotal.getTick()) {
            values.add(new BarEntry(i, (float) kline.getData().getVol(), kline.getData()));

            i++;
        }
        return values;
    }


    @Override
    protected int getLayoutId() {
        return R.layout.tmmarket_fragment_market_kline;
    }


    // ---------------------------------event-------------------------------------

    @Subscriber
    public void onGetMarketList(BaseEvent event) {
        if (event.getCode() == BaseEvent.EventCode.WS_KLINE_OPEN) {
            if (isVisiable && mIsPrepared && !isAlreadySubed) {
                subMarketDetail();
                reqMarketDetail();
            }
        }

    }


}
